﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.Data;
using System.Data.OleDb;
using System.Windows.Forms;

namespace Compte
{
    class AccesDB
    {
        public enum Access { SqlClient = 1, OleDB };
        public string Chemin { get; set; }
        public Access Acces { get; set; }

        public AccesDB(String chemin, Access modeDAcces)
        {
            this.Chemin = chemin;
            this.Acces = modeDAcces;
        }

        private object ExecMetode(String nom, Type[] paramMethod, object[] param)
        {
            System.Reflection.MethodInfo me = typeof(AccesDB).GetMethod(nom + Acces.ToString(), paramMethod);
            return me.Invoke(this, param);
        }

        private SqlConnection obtenirConnectionSqlClient()
        {
            SqlConnection cn = new SqlConnection(Chemin);
            try { cn.Open(); }
            catch (Exception) { return null; }
            return cn;
        }
        private OleDbConnection obtenirConnectionOleDB()
        {
            OleDbConnection cn = new OleDbConnection(Chemin);
            try { cn.Open(); }
            catch (Exception) { return null; }
            return cn;
            //cn.ConnectionString = @"Provider=Microsoft.Jet.OLEDB.4.0;Data source= " + AppDomain.CurrentDomain.BaseDirectory + @"\Budget.mdb";
        }

        private SqlDataReader SQLRechercheSqlClient(string requete, SQLParameter[] param)
        {
            SqlConnection cn = obtenirConnectionSqlClient();
            if (cn == null)
            {
                return null;
            }

            SqlCommand cmd = new SqlCommand(requete, cn);

            foreach (SQLParameter p in param)
            {
                cmd.Parameters.AddWithValue(p.Nom, p.Value);
            }

            SqlDataReader dr;

            // S'assure que la requête ne génère pas d'erreures
            try
            {
                dr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
                cn.Close();
                return dr;
            }
            catch (SqlException e)
            {
                MessageBox.Show(e.Message);
                return null;
            }
        }
        private OleDbDataReader SQLRechercheOleDB(string requete, SQLParameter[] param)
        {
            OleDbConnection cn = obtenirConnectionOleDB();
            if (cn == null)
            {
                return null;
            }

            OleDbCommand cmd = new OleDbCommand(requete, cn);

            foreach (SQLParameter p in param)
            {
                cmd.Parameters.AddWithValue(p.Nom, p.Value);
            }

            OleDbDataReader dr;

            // S'assure que la requête ne génère pas d'erreures
            try
            {
                dr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
                cn.Close();
                return dr;
            }
            catch (SqlException e)
            {
                MessageBox.Show(e.Message);
                return null;
            }
        }

        private List<object[]> SelectSqlClient(string requete, SQLParameter[] param)
        {
            SqlDataReader dr = SQLRechercheSqlClient(requete, param);

            if (dr == null)
                return null;

            //Créer une liste de tableaux de string
            List<object[]> rows = new List<object[]>();

            //Pour chaque champ, ajoute à la liste d'objet du champ correspondant l'information de la cellule
            while (dr.Read())
            {
                //Crée un tableau de string qui représente une rangée
                object[] row = new object[dr.FieldCount];

                // Pour chaque champ de la rangée, ajoute l'information correspondante à la cellule
                for (int a = 0; a < dr.FieldCount; a++)
                {
                    row[a] = dr.GetValue(a);
                }

                //Ajoute la rangée à la liste
                rows.Add(row);
            }
            dr.Close();
            return rows;
        }
        private List<object[]> SelectOleDB(string requete, SQLParameter[] param)
        {
            OleDbDataReader dr = SQLRechercheOleDB(requete, param);

            if (dr == null)
                return null;

            //Créer une liste de tableaux de string
            List<object[]> rows = new List<object[]>();

            //Pour chaque champ, ajoute à la liste d'objet du champ correspondant l'information de la cellule
            while (dr.Read())
            {
                //Crée un tableau de string qui représente une rangée
                object[] row = new object[dr.FieldCount];

                // Pour chaque champ de la rangée, ajoute l'information correspondante à la cellule
                for (int a = 0; a < dr.FieldCount; a++)
                {
                    row[a] = dr.GetValue(a);
                }

                //Ajoute la rangée à la liste
                rows.Add(row);
            }
            dr.Close();
            return rows;
        }

        private void ExecNonQuerySqlClient(String requete, SQLParameter[] ps)
        {
            SqlConnection cn = obtenirConnectionSqlClient();
            if (cn == null)
            {
                return;
            }
            SqlCommand cmd = new SqlCommand(requete, cn);
            foreach (SQLParameter p in ps)
            {
                if (p.Value != null)
                {
                    cmd.Parameters.AddWithValue("@" + p.Nom, p.Value);
                }
            }
            cmd.ExecuteNonQuery();
            cn.Close();
        }
        private void ExecNonQueryOleDB(String requete, SQLParameter[] ps)
        {
            OleDbConnection cn = obtenirConnectionOleDB();
            if (cn == null)
            {
                return;
            }
            OleDbCommand cmd = new OleDbCommand(requete, cn);
            foreach (SQLParameter p in ps)
            {
                if (p.Value != null)
                {
                    cmd.Parameters.AddWithValue("@" + p.Nom, p.Value);
                }
            }
            cmd.ExecuteNonQuery();
            cn.Close();
        }

        public List<object[]> SelectObject(string requete)
        {
            return (List<object[]>)ExecMetode("Select", new Type[] { typeof(String), typeof(SQLParameter[]) }, new object[] { requete, new SQLParameter[] { } });
        }
        public List<object[]> SelectObject(string requete, SQLParameter[] param)
        {
            return (List<object[]>)ExecMetode("Select", new Type[] { typeof(String), typeof(SQLParameter[]) }, new object[] { requete, param });
        }

        public List<T> SelectGeneric<T>(string requete, Type[] propriete)
        {
            List<object[]> result = (List<object[]>)ExecMetode("Select", new Type[] { typeof(String), typeof(SQLParameter[]) }, new object[] { requete, new SQLParameter[] { } });
            List<T> rep = new List<T>();

            if (result == null)
                return null;

            foreach (object[] ligne in result)
            {
                rep.Add((T)typeof(T).GetConstructor(propriete).Invoke(ligne));
            }

            return rep;
        }
        public List<T> SelectGeneric<T>(string requete, Type[] propriete, SQLParameter[] param)
        {
            List<object[]> result = (List<object[]>)ExecMetode("Select", new Type[] { typeof(String), typeof(SQLParameter[]) }, new object[] { requete, param });
            List<T> rep = new List<T>();

            if (result == null)
                return null;

            foreach (object[] ligne in result)
            {
                rep.Add((T)typeof(T).GetConstructor(propriete).Invoke(ligne));
            }

            return rep;
        }

        public void Insert<T>(T instance) where T : SQLExec
        {
            SQLParameter[] ps;
            if (instance.clefIsAuto())
                ps = instance.GetElements();
            else
            {
                ps = new SQLParameter[instance.GetElements().Count() + instance.GetClef().Count()];
                for (int a = 0; a < instance.GetClef().Count(); a++)
                    ps[a] = instance.GetClef()[a];

                for (int a = instance.GetClef().Count(); a < ps.Count(); a++)
                    ps[a] = instance.GetElements()[a - instance.GetClef().Count()];
            }

            string requete = "INSERT INTO " + instance.GetTable();
            string nom = " (";
            string valeur = " (";

            foreach (SQLParameter p in ps)
            {
                if (p.Value != null)
                {
                    nom += p.Nom + ",";
                    valeur += "@" + p.Nom + ",";
                }
            }
            nom = nom.Substring(0, nom.Length - 1) + ") ";
            valeur = valeur.Substring(0, valeur.Length - 1) + ") ";

            requete += nom + " VALUES " + valeur;

            List<SQLParameter> param = new List<SQLParameter>();
            foreach (SQLParameter p in ps)
            {
                if (p.Value != null)
                {
                    param.Add(p);
                }
            }

            ExecMetode("ExecNonQuery", new Type[] { typeof(String), typeof(SQLParameter[]) }, new object[] { requete, param.ToArray() });
        }

        public void Delete<T>(T instance) where T : SQLExec
        {
            string requete = "DELETE FROM " + instance.GetTable() + " WHERE ";
            foreach (SQLParameter p in instance.GetClef())
            {
                requete += p.Nom + " = @" + p.Nom + " and ";
            }
            requete = requete.Substring(0, requete.Count() - 5);
            ExecMetode("ExecNonQuery", new Type[] { typeof(String), typeof(SQLParameter[]) }, new object[] { requete, instance.GetClef() });
        }

        public void Update<T>(T instance) where T : SQLExec
        {
            string requete = "UPDATE" + instance.GetTable() + " SET ";
            if (!instance.clefIsAuto())
            {
                foreach (SQLParameter p in instance.GetClef())
                {
                    if (p.Value != null)
                        requete += p.Nom + " = @" + p.Nom + ",";
                }
            }
            foreach (SQLParameter p in instance.GetElements())
            {
                if (p.Value != null)
                    requete += p.Nom + " = @" + p.Nom + ",";
            }
            requete = requete.Substring(0, requete.Count() - 1);
            requete += " WHERE ";
            foreach (SQLParameter p in instance.GetClef())
            {
                requete += p.Nom + " = @" + p.Nom + " and ";
            }
            requete = requete.Substring(0, requete.Count() - 5);

            List<SQLParameter> param = new List<SQLParameter>();

            if (!instance.clefIsAuto())
            {
                param.AddRange(instance.GetClef());
            }
            foreach (SQLParameter p in instance.GetElements())
            {
                if (p.Value != null)
                    param.Add(p);
            }

            ExecMetode("ExecNonQuery", new Type[] { typeof(String), typeof(SQLParameter[]) }, new object[] { requete, param.ToArray() });
        }
    }
}